package jrain.fw.script.expression;

import java.util.List;
import java.util.Map;

import jrain.fw.script.operator.BinaryOperator;
import jrain.fw.script.operator.Coercions;
import jrain.fw.script.resolver.VariableResolver;
import jrain.fw.script.tools.ELException;
import jrain.fw.script.tools.Logger;
 
public class BinaryOperatorExpression extends Expression {
	// -------------------------------------
	// Properties
	// -------------------------------------
	// property expression

	Expression mExpression;

	public Expression getExpression() {
		return mExpression;
	}

	public void setExpression(Expression pExpression) {
		mExpression = pExpression;
	}

	// -------------------------------------
	// property operators

	List<?> mOperators;

	public List<?> getOperators() {
		return mOperators;
	}

	public void setOperators(List<?> pOperators) {
		mOperators = pOperators;
	}

	// -------------------------------------
	// property expressions

	List<?> mExpressions;

	public List<?> getExpressions() {
		return mExpressions;
	}

	public void setExpressions(List<?> pExpressions) {
		mExpressions = pExpressions;
	}

	// -------------------------------------

	/**
	 * Constructor
	 */
	public BinaryOperatorExpression(Expression pExpression, List<?> pOperators, List<?> pExpressions) {
		mExpression = pExpression;
		mOperators = pOperators;
		mExpressions = pExpressions;
	}

	// -------------------------------------
	// Expression methods
	// -------------------------------------

	/**
	 * Returns the expression in the expression language syntax
	 */
	public String getExpressionString() {
		StringBuffer buf = new StringBuffer();
		buf.append("(");
		buf.append(mExpression.getExpressionString());
		for (int i = 0; i < mOperators.size(); i++) {
			BinaryOperator operator = (BinaryOperator) mOperators.get(i);
			Expression expression = (Expression) mExpressions.get(i);
			buf.append(" ");
			buf.append(operator.getOperatorSymbol());
			buf.append(" ");
			buf.append(expression.getExpressionString());
		}
		buf.append(")");

		return buf.toString();
	}

	// -------------------------------------

	/**
	 * Evaluates to the literal value
	 */
	public Object evaluate(Object pContext, VariableResolver pResolver, Map<Object, Object> functions, String defaultPrefix, Logger pLogger)
			throws ELException {
		Object value = mExpression.evaluate(pContext, pResolver, functions, defaultPrefix, pLogger);
		for (int i = 0; i < mOperators.size(); i++) {
			BinaryOperator operator = (BinaryOperator) mOperators.get(i);

			// For the And/Or operators, we need to coerce to a boolean
			// before testing if we shouldEvaluate
			if (operator.shouldCoerceToBoolean()) {
				value = Coercions.coerceToBoolean(value, pLogger);
			}

			if (operator.shouldEvaluate(value)) {
				Expression expression = (Expression) mExpressions.get(i);
				Object nextValue = expression.evaluate(pContext, pResolver, functions, defaultPrefix, pLogger);

				value = operator.apply(value, nextValue, pContext, pLogger);
			}
		}
		return value;
	}

	// -------------------------------------
}
